package com.egg.basic.service.quartz;

import cn.hutool.core.util.ObjectUtil;
import com.egg.basic.entity.quartz.Quartz;
import com.egg.common.spring.util.SpringContextUtil;
import lombok.extern.slf4j.Slf4j;
import org.quartz.JobExecutionContext;
import org.springframework.scheduling.annotation.Async;
import org.springframework.scheduling.quartz.QuartzJobBean;
import org.springframework.util.ReflectionUtils;

import java.lang.reflect.Method;
import java.util.concurrent.ArrayBlockingQueue;
import java.util.concurrent.Callable;
import java.util.concurrent.Future;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;

@Slf4j
@Async
public class QuartzExecution extends QuartzJobBean {


    public static ThreadPoolExecutor getPool() {
        return new ThreadPoolExecutor(
                10,
                30,
                60,
                TimeUnit.SECONDS,
                new ArrayBlockingQueue<>(50)
        );
    }

    /**
     * 该处仅供参考
     */
    private static final ThreadPoolExecutor EXECUTOR = getPool();

    class QuartzCallable implements Callable<Object> {

        private final Object bean;
        private final Method method;
        private final String params;

        QuartzCallable(String beanName, String methodName, String params) throws NoSuchMethodException {
            this.bean = SpringContextUtil.getBean(beanName);
            this.params = params;
            if (ObjectUtil.isEmpty(params)) {
                this.method = this.bean.getClass().getDeclaredMethod(methodName);
            } else {
                this.method = this.bean.getClass().getDeclaredMethod(methodName, String.class);
            }
        }

        @Override
        public Object call() throws Exception {
            ReflectionUtils.makeAccessible(method);
            if (ObjectUtil.isNotEmpty(params)) {
                method.invoke(bean, params);
            } else {
                method.invoke(bean);
            }
            return null;
        }
    }


    @Override
    public void executeInternal(JobExecutionContext context) {
        Quartz quartz = (Quartz) context.getMergedJobDataMap().get(QuartzManage.JOB_KEY);
        try {
            // 执行任务
            QuartzCallable quartzCallable = new QuartzCallable(
                    quartz.getBeanName()
                    , quartz.getMethodName()
                    , quartz.getParams()
            );
            Future<?> future = EXECUTOR.submit(quartzCallable);
            future.get();
        } catch (Exception e) {
            // 任务如果失败了则暂停
            if (quartz.getPauseAfterFailure()) {
                //更新状态
                QuartzServiceImpl quartzJobService = SpringContextUtil.getBean(QuartzServiceImpl.class);
                quartzJobService.pauseById(quartz.getId());
            }
        }
    }


}
